package com.lksoft.bz;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;

import javax.swing.JList;

public class StitchPrinter implements Printable {
	
	/** Space between stitch and legend */
	private static final int LEGEND_SPACE = 5;
	/** Legend zoom */
	private static final double LEGEND_ZOOM = 0.7;
	
	
	// The stitch panel
	private StitchPanel panel;
	// The legend (usedBeads)
	private JList<BeadUsage> usedBeads;
	
	// Page infos
	int numPagesX;
	int numPagesY;
	
	// Legends fits on first page or not
	int legendPages;
	
	// Zoom level
	float zoom = 2.0f;
	// Show frame
	boolean showFrame = true;

	/**
	 * Construct with a stitch panel
	 * @param stitchPanel
	 */
	public StitchPrinter(StitchPanel stitchPanel, JList<BeadUsage> usedBeads) {
		this.panel = stitchPanel;
		this.usedBeads = usedBeads;
	}

	@Override
	public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
		// Calculate required pages number
		float oldZoom = panel.getZoomFactor();
		boolean oldFrame = panel.isShowFrame();
		
		calculateNumPaged(pf);
		int numPages = numPagesX*numPagesY + legendPages;
				
		if( page >= numPages ) return NO_SUCH_PAGE;
		
		// Saves old transform
		AffineTransform old = ((Graphics2D)g).getTransform();
		
		// Stitch page
		if( page < numPages-legendPages ){
			int pageX = page/numPagesY;
			int pageY = page%numPagesY;
			
			int oX = (int)(pf.getImageableX() - pageX*pf.getImageableWidth() - StitchPanel.STITCH_X);
			int oY = (int)(pf.getImageableY() - pageY*pf.getImageableHeight() - StitchPanel.STITCH_Y);
			g.translate(oX, oY);
			
			panel.setZoomFactor(zoom);
			panel.setShowFrame(showFrame);
			panel.print(g);
			
			// Print legend
			if( legendPages == 0 ){
				g.translate(panel.getStitchWidth()+LEGEND_SPACE+StitchPanel.STITCH_X, StitchPanel.STITCH_Y);
				((Graphics2D)g).scale(LEGEND_ZOOM, LEGEND_ZOOM);
				usedBeads.printAll(g);
			}
		}
		else{
			int pageY = page - (numPages-legendPages);
			
			// Legend page
			g.translate((int)pf.getImageableX(), (int)(pf.getImageableY() - pageY*pf.getImageableHeight()));
			((Graphics2D)g).scale(LEGEND_ZOOM, LEGEND_ZOOM);
			usedBeads.printAll(g);
		}
		
		// Reset zoom and transform
		panel.setZoomFactor(oldZoom);
		panel.setShowFrame(oldFrame);
		((Graphics2D)g).setTransform(old);
		return PAGE_EXISTS;
	}

	/**
	 * Calculate the number of pages needed in X and Y direction
	 * 
	 * @param pf The page format
	 * @return
	 */
	private void calculateNumPaged(PageFormat pf) {		
		panel.setZoomFactor(zoom);
		int fullWidth = panel.getStitchWidth();
		int legendWidth = (int) (usedBeads.getWidth() * LEGEND_ZOOM);
		int legendHeight = (int) (usedBeads.getWidth() * LEGEND_ZOOM);
		boolean legendFits = pf.getImageableWidth() >= fullWidth + legendWidth + LEGEND_SPACE;
		int fullHeight = legendFits ? Math.max(panel.getStitchHeight(), legendHeight) : panel.getStitchHeight();
		
		numPagesX = ((int) (fullWidth / pf.getImageableWidth())+1);
		numPagesY = ((int) (fullHeight / pf.getImageableHeight())+1);
		
		// If legend fits, in first page, print togheter
		if( legendFits ){
			legendPages = 0;
		}
		else{
			legendPages = (int) (legendHeight / pf.getImageableHeight())+1;
		}
	}

	/**
	 * @return the zoom
	 */
	public float getZoom() {
		return zoom;
	}

	/**
	 * @param zoom the zoom to set
	 */
	public void setZoom(float zoom) {
		this.zoom = zoom;
	}
	
	/**
	 * Show frame
	 * @param bool
	 */
	public void setShowFrame(boolean showFrame){
		this.showFrame = showFrame;
	}
	
	/**
	 * @return Whether showing frame or not
	 */
	public boolean isShowFrame(){
		return showFrame;
	}

}
